<?php

declare (strict_types = 1);

namespace app\common\repository;

use app\common\model\BaseModel as Model;
use Exception;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;

class BaseRepository
{
    protected Model $model;

    public function __construct(Model $model)
    {
        $this->model = $model;
    }

    /**
     * 获取模型实例
     *
     * @return Model
     */
    protected function getModel(): Model
    {
        return $this->model;
    }

    /**
     * 设置模型
     *
     * @param $model
     * @return mixed
     */
    protected function setModel($model): mixed
    {
        return $this->model = $model;
    }

    /**
     * 获取主键
     *
     * @return string|int 返回主键名称或值
     */
    public function getPk(): int|string|bool
    {
        return $this->getModel()->getPk() ?? false;
    }
    
    /**
     * 分页查询
     *
     * @param array $where 查询条件
     * @param array $order 排序规则
     * @param int $page 当前页码
     * @param int $pageSize 每页记录数
     * @return array 返回分页数据，包含总记录数和记录列表
     * @throws DataNotFoundException
     * @throws DbException
     */
    public function paginate(array $where = [], array $order = [], int $page = 1, int $pageSize = 15): array
    {
        // 构建查询
        $query = $this->model->where($where);

        // 排序
        if (!empty($order)) {
            foreach ($order as $field => $direction) {
                $query->order($field, $direction);
            }
        } else {
            // 默认主键排序
            $query->order($this->getPk(), 'desc');
        }

        // 分页查询
        $paginator = $query->paginate([
            'page' => $page,
            'list_rows' => $pageSize,
        ]);

        // 返回分页数据
        return [
            'total' => $paginator->total(),
            'list' => $paginator->items(),
        ];
    }

    /**
     * 根据条件获取多条记录
     *
     * @param array $where 查询条件
     * @param array $order 排序规则
     * @param array $field 查询字段
     * @param int $limit 返回记录数量限制
     * @return \think\model\Collection|Collection
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getByWhere(array $where = [], array $order = [], array $field = ['*'], int $limit = 0): \think\model\Collection|Collection
    {
        $query = $this->model->where($where)->field($field);

        if (!empty($order)) {
            foreach ($order as $field => $direction) {
                $query->order($field, $direction);
            }
        } else {
            // 默认主键排序
            $query->order($this->getPk(), 'desc');
        }
    
        if ($limit > 0) {
            $query->limit($limit);
        }
    
        return $query->field($field)->select();
    }

    /**
     * 获取一条记录
     *
     * @param mixed $where
     * @param array $field
     * @param array $order
     * @return Model|array|mixed
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getOne(mixed $where, array $field = ['*'], array $order = []): mixed
    {
        if(!is_array($where)) {
            $where = [$this->getPk() => $where];
        }
        return $this->model->order($order)->where($where)->field($field)->find();
    }

    /**
     * 获取某一列的数据
     *
     * @param string $column 列名
     * @param array $where 查询条件（可选）
     * @param string|null $indexKey 索引列名（可选）
     * @return array
     */
    public function getColumn(string $column, array $where = [], ?string $indexKey = null): array
    {
        $query = $this->model->where($where);
        // 如果 $indexKey 为 null，则不传递第二个参数
        if ($indexKey === null) {
            return $query->column($column);
        }
        return $query->column($column, $indexKey);
    }

    /**
     * 获取某条数据中的值
     *
     * @param string $key 获取的字段名
     * @param mixed $where 查询条件
     * @return mixed
     */
    public function getValue(string $key, mixed $where): mixed
    {
        // 如果不是数组则主键查询
        if(!is_array($where)) {
            $where = [$this->getPk() => $where];
        }
        return $this->model->where($where)->value($key);
    }

    /**
     * 添加一条或多条记录
     *
     * @param array $data
     * @return Model|array|Collection|\think\model\contract\Modelable
     * @throws Exception
     */
    public function save(array $data)
    {
        // 如果 $data 是一个二维数组，则认为是批量插入
        if (isset($data[0]) && is_array($data[0])) {
            // 批量插入
            return $this->model->saveAll($data);
        } else {
            // 单条插入
            return $this->model->create($data);
        }
    }

    /**
     * 条件更新记录
     *
     * @param array $data 数据
     * @param $where
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function update(array $data, $where)
    {
        if (is_array($where)) {
            // 如果 $where 是数组，则认为是条件更新
            return $this->model->where($where)->update($data);
        } else {
            // 如果 $where 是主键值，则更新单条记录
            $query = $this->model->find($where);
            return $query->save($data);
        }
    }

    /**
     * 批量添加/更新数据
     *
     * @param array $data 数据
     * @return Collection
     * @throws Exception
     */
    public function saveAll(array $data): Collection
    {
        return $this->model->saveAll($data);
    }


    /**
     * 删除数据
     *
     * @param $where
     * @return bool
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function delete($where): bool
    {
        // 情况1: 关联数组条件删除 (例如: ['status' => 0])
        if (is_array($where) && array_values($where) !== $where) {
            $result = $this->model->where($where)->select();
            if($result) {
                $result->delete();
                return true;
            } else {
                return true;
            }
        }

        // 情况2: 索引数组批量ID删除 (例如: [1,2,3])
        if (is_array($where) && array_values($where) === $where) {
            if (!empty($where)) {
                $result = $this->model->destroy($where); // 使用模型批量删除方法
                return $result !== false && $result > 0; // 成功返回true，失败返回false
            } else {
                return true; // 如果没有要删除的记录，也视为成功
            }
        }

        // 情况3: 标量值单个删除 (例如: 123 或 '123')
        if (is_scalar($where) && !empty($where)) {
            // 直接通过主键删除 (自动处理软删除等情况)
            $result = $this->model->destroy($where);
            return $result !== false && $result > 0; // 成功返回true，失败返回false
        }

        // 如果未匹配任何情况，则视为失败
        return false;
    }
//    public function delete($where): bool
//    {
//        // 情况1: 关联数组条件删除 (例如: ['status' => 0])
//        if (is_array($where) && array_keys($where) !== range(0, count($where) - 1)) {
//            $result = $this->model->where($where)->find();
//            if ($result) {
//                $result->delete();
//                return true;
//            } else {
//                throw new AdminException('数据不存在！');
//            }
//        }
//
//        // 情况2: 索引数组批量ID删除 (例如: [1, 2, 3])
//        if (is_array($where) && array_keys($where) === range(0, count($where) - 1)) {
//            if (!empty($where)) {
//                $result = $this->model->destroy($where); // 使用模型批量删除方法
//                return $result !== false && $result > 0; // 成功返回true，失败返回false
//            } else {
//                return true; // 如果没有要删除的记录，也视为成功
//            }
//        }
//
//        // 情况3: 标量值单个删除 (例如: 123 或 '123')
//        if (is_scalar($where) && !empty($where)) {
//            // 直接通过主键删除 (自动处理软删除等情况)
//            $result = $this->model->destroy($where);
//            return $result !== false && $result > 0; // 成功返回true，失败返回false
//        }
//
//        // 新增情况4: 批量条件删除 (例如 [['status' => 0], ['category_id' => 5]])
//        if (is_array($where) && array_keys($where) === range(0, count($where) - 1) && is_array($where[0])) {
//            $orConditions = [];
//            foreach ($where as $condition) {
//                if (is_array($condition)) {
//                    $orConditions[] = $condition;
//                } else {
//                    throw new AdminException('批量条件删除时，每个条件必须是关联数组');
//                }
//            }
//
//            // 使用 OR 条件组合批量删除
//            $query = $this->model;
//            foreach ($orConditions as $index => $condition) {
//                if ($index === 0) {
//                    $query = $query->where($condition);
//                } else {
//                    $query = $query->whereOr($condition);
//                }
//            }
//
//            $result = $query->delete();
//            return $result !== false && $result > 0; // 成功返回true，失败返回false
//        }
//
//        // 如果未匹配任何情况，则视为失败
//        return false;
//    }

    /**
     * 自增/自减
     *
     * @param int|string|array $where 查询条件
     * @param string $field 查询字段
     * @param string $type inc:自增 dec:自减
     * @param int|float $step 步数
     * @return bool
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function setInc(int|string|array $where, string $field, string $type = 'inc', int|float $step = 1): bool
    {
        // 如果不是数组则主键查询
        if(!is_array($where)) {
            $where = [$this->getPk() => $where];
        }
        $query = $this->model->where($where)->find();
        if($type === 'inc') {
            // 增加
            $result = $query->inc($field, $step)->save();
        } else {
            // 减少
            $result = $query->dec($field, $step)->save();
        }
        return $result;
    }

    /**
     * 求值总和
     *
     * @param array $where 查询条件
     * @param string $field 查询字段
     * @return float
     */
    public function sum(array $where = [], string $field = '*'): float
    {
        return $this->model->where($where)->sum($field);
    }

    /**
     * 计算行数
     *
     * @param array $where 查询条件
     * @return int
     */
    public function getCount(array $where = []): int
    {
        return $this->model->where($where)->count();
    }

    /**
     * 获取锁定的记录（用于防止超卖）
     *
     * @param int|string $id
     * @return \think\Model|null
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function findWithLock(int|string $id): ?\think\Model
    {
        return $this->model->lock(true)->find($id);
    }
}